package com.example.ota_ble.ble.ota.mcu

import android.util.Log
import com.example.ota_ble.ble.component.ota_lock.ota_ctrl_lock
import com.example.ota_ble.ble.component.ota_lock.ota_data_lock

import com.example.ota_ble.crc.crc16
import kotlin.experimental.and
import kotlin.experimental.or
data object OPCODE_DEU{

     var dfu_opcode_none:   UByte = 0x00.toUByte()
     var dfu_opcode_inquiry: UByte = 0x10.toUByte()
     var dfu_opcode_boot   : UByte  = 0x11.toUByte()
     var dfu_opcode_unlock : UByte  = 0x1a.toUByte()
     var dfu_opcode_reset  : UByte = 0x1f.toUByte()
     var dfu_opcode_erase  : UByte = 0x20.toUByte()
     var dfu_opcode_read   : UByte = 0x21.toUByte()
     var dfu_opcode_write  : UByte = 0x22.toUByte()
     var dfu_opcode_verify : UByte = 0x23.toUByte()
     var dfu_opcode_end    :  UByte = 0x24.toUByte()

    fun check_opcode(opcode : UByte) : Boolean
    {
        return  (opcode == dfu_opcode_none) or (opcode == dfu_opcode_inquiry)or (opcode == dfu_opcode_boot)or (opcode == dfu_opcode_unlock) or
        (opcode == dfu_opcode_reset) or (opcode == dfu_opcode_erase)or (opcode == dfu_opcode_read) or (opcode == dfu_opcode_write) or
        (opcode == dfu_opcode_verify) or (opcode == dfu_opcode_end)

    }

}
object parseNotify {
    var TAG = "rocjan.parseNotify"
    var protof_head: UByte = 0xaa.toUByte()
    var protof_tail: UByte = 0x55.toUByte()
    fun parse(data: ByteArray)
    {
        var head: UByte
        var opcode: UByte
        var length: UShort
        var load: ByteArray
        var crc_check: UShort
        var tail: UByte
        if(data.size <= 7 ) {
            Log.e(TAG,"data.size <= 7")
            return
        }
        Log.i(TAG,data.joinToString(", "){"0x" + it.toByte().toString(16).padStart(2,'0')})
        head = data[0].toUByte()

        if(head != protof_head) {
            Log.e(TAG,"head != protof_head")
            return
        }
        opcode = data[1].toUByte()

        if(!OPCODE_DEU.check_opcode(opcode)) {
            Log.e(TAG,"!OPCODE_DEU.check_opcode(opcode)")
            return
        }
        length = data[2].toUShort() or ((data[3].toInt() shl 8).toUShort())
        if( length == 0.toUShort()) {
            Log.e(TAG,"length = 0")
            return
        }
        load = data.copyOfRange(4,4+length.toInt())
        if( length != load.size.toUShort()) {
            Log.e(TAG," length != load.size.toUShort()")
            return
        }
        crc_check = (data[data.size - 3].toUShort() and 0xff.toUShort()) or (data[data.size - 2].toUInt() shl 8).toUShort()
        var crc_c = crc16.calculateCRC16(load,load.size)
        if( crc_check != crc_c) {
            Log.e(TAG," crc_check != crc_c crc err")
            return
        }
        tail = data[data.size - 1].toUByte()
        if( tail != protof_tail) {
            Log.e(TAG," tail != protof_tail")
            return
        }
        var ret:Boolean = false
        when(opcode)
        {
            OPCODE_DEU.dfu_opcode_inquiry ->{
                ret = opcode_handle.inquiry(load)

            }
            OPCODE_DEU.dfu_opcode_boot ->{
                ret = opcode_handle.boot(load)
            }
            OPCODE_DEU.dfu_opcode_unlock ->{
                ret = opcode_handle.unlock(load)
            }
            OPCODE_DEU.dfu_opcode_reset ->{
                ret = opcode_handle.reset (load)
            }
            OPCODE_DEU.dfu_opcode_erase ->{
                ret = opcode_handle.erase(load)
            }
            OPCODE_DEU.dfu_opcode_read ->{
                ret = opcode_handle.read (load)
            }
            OPCODE_DEU.dfu_opcode_verify ->{
                ret = opcode_handle.verify(load)
            }
            OPCODE_DEU.dfu_opcode_write ->{
                ret = opcode_handle.write(load)
            }
            else  ->{
                ret = opcode_handle.other(load)
            }
        }
        if(opcode==OPCODE_DEU.dfu_opcode_write)
        {
            if(ret!=false)
            {
                Log.i(TAG,"ACK  = 0")
                ota_data_lock.trySend(0).isSuccess
            }else{

                Log.i(TAG,"ACK  = -1")
                ota_data_lock.trySend(-1).isSuccess
            }
        }
        else{
            if(ret!=false)
            {
                Log.i(TAG,"ACK  = 0")
                ota_ctrl_lock.trySend(0).isSuccess
            }else{

                Log.i(TAG,"ACK  = -1")
                ota_ctrl_lock.trySend(-1).isSuccess
            }
        }
        Log.i(TAG,"head:0x"+ head.toString(16).padStart(2,'0'))
        Log.i(TAG,"opcode:0x" + opcode.toString(16).padStart(2,'0'))
        Log.i(TAG,"length:0x${length.toString(16).padStart(2,'0')}")
        Log.i(TAG,load.joinToString(", "){"0x" + it.toByte().toString(16).padStart(2,'0')})
        Log.i(TAG,"crc:0x" + crc_check.toUInt().toUByte().toString() + " 0x" + (crc_check.toUInt() shr 8).toUByte().toString() )
        Log.i(TAG,"tail:0x${tail.toString(16).padStart(2,'0')}")
        Log.i(TAG,"crc:0x" + crc_c.toUInt().toUByte().toString() + " 0x" + (crc_c.toUInt() shr 8).toUByte().toString() )
    }


    private  object opcode_handle
    {
        fun inquiry(data: ByteArray): Boolean
        {
            Log.i(TAG,"处理opcode_handle通知，inquiry 中....")

            return true
        }
        fun boot(data: ByteArray): Boolean
        {
            Log.i(TAG,"处理opcode_handle通知，boot 中....")
            return data[0] == 0.toByte()
        }
        fun unlock(data: ByteArray): Boolean
        {
            Log.i(TAG,"处理opcode_handle通知，unlock 中....")
            return data[0] == 0.toByte()
        }
        fun reset(data: ByteArray): Boolean
        {
            Log.i(TAG,"处理opcode_handle通知，reset 中....")
            return data[0] == 0.toByte()
        }
        fun erase(data: ByteArray): Boolean
        {
            Log.i(TAG,"处理opcode_handle通知，erase 中....")
            return data[0] == 0.toByte()
        }
        fun read(data: ByteArray): Boolean
        {
            Log.i(TAG,"处理opcode_handle通知，read 中....")
            return data[0] == 0.toByte()
        }
        fun write(data: ByteArray): Boolean
        {
            Log.i(TAG,"处理opcode_handle通知，write 中....")
            return data[0] == 0.toByte()
        }
        fun verify(data: ByteArray): Boolean
        {
            Log.i(TAG,"处理opcode_handle通知，verify 中....")
            return data[0] == 0.toByte()
        }
        fun other(data: ByteArray): Boolean
        {
            Log.i(TAG,"处理opcode_handle通知，other 中....")
            return data[0] == 0.toByte()
        }
    }
}
